In this project, I will analyze data from the New York City school department to understand whether parent, teacher and student perceptions of the following factors affect average school SAT scores(an indicator of academic performance):

  1. Safety
  2. Engagement
  3. Communication
  4. Academics

I’ll start by installing the packages needed for this analysis

library(readr)
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
library(dplyr)
library(stringr)
library(purrr)
library(tidyr)
library(ggplot2)
library(readxl)

In this project, we’ll be investigating the following questions:
1. Do student, teacher, and parent perceptions of NYC school quality appear to be related to demographic and academic success metrics? 2. Do students, teachers, and parents have similar perceptions of NYC school quality?

Importing Data

survey_dict <- read_xls("Survey Data Dictionary.xls")
New names:
* `` -> ...2
survey_dict

Survey Data Dictionary.xls, contains metadata that will be useful to decide how to clean and prepare the survey data for analysis.

survey_data_gen <- read_tsv("masterfile11_gened_final.txt")
Parsed with column specification:
cols(
  .default = col_double(),
  dbn = col_character(),
  bn = col_character(),
  schoolname = col_character(),
  studentssurveyed = col_character(),
  schooltype = col_character(),
  p_q1 = col_logical(),
  p_q3d = col_logical(),
  p_q9 = col_logical(),
  p_q10 = col_logical(),
  p_q12aa = col_logical(),
  p_q12ab = col_logical(),
  p_q12ac = col_logical(),
  p_q12ad = col_logical(),
  p_q12ba = col_logical(),
  p_q12bb = col_logical(),
  p_q12bc = col_logical(),
  p_q12bd = col_logical(),
  t_q6m = col_logical(),
  t_q9 = col_logical(),
  t_q10a = col_logical()
  # ... with 18 more columns
)
See spec(...) for full column specifications.
survey_data_gen

The masterfile11_gened_final.txt file, contain survey data for “general education” schools — those that do not specifically serve populations with special needs.

survey_data_dis <- read_tsv("masterfile11_d75_final.txt")
Parsed with column specification:
cols(
  .default = col_double(),
  dbn = col_character(),
  bn = col_character(),
  schoolname = col_character(),
  studentssurveyed = col_character(),
  schooltype = col_character(),
  p_q5 = col_logical(),
  p_q9 = col_logical(),
  p_q13a = col_logical(),
  p_q13b = col_logical(),
  p_q13c = col_logical(),
  p_q13d = col_logical(),
  p_q14a = col_logical(),
  p_q14b = col_logical(),
  p_q14c = col_logical(),
  p_q14d = col_logical(),
  t_q11a = col_logical(),
  t_q11b = col_logical(),
  t_q14 = col_logical(),
  t_q15a = col_logical(),
  t_q15b = col_logical()
  # ... with 14 more columns
)
See spec(...) for full column specifications.
survey_data_dis

The masterfile11_d75_final.txt file contain survey data for District 75 schools, which provide special education support for children with special needs such as learning or physical disabilities.

combined <- read_csv("combined.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  dbn = col_character(),
  school_name = col_character(),
  boro = col_character(),
  location = col_character()
)
See spec(...) for full column specifications.
combined

Simplifying DataFrames

survey_data_gen <- survey_data_gen %>% select(dbn,schoolname,schooltype,saf_p_11,com_p_11,eng_p_11,aca_p_11,saf_t_11,com_t_11,eng_t_11,aca_t_11,saf_s_11,com_s_11,  
eng_s_11,aca_s_11,saf_tot_11,com_tot_11,eng_tot_11,aca_tot_11) %>% filter(schooltype == "High School")
survey_data_gen

I’m simplifying dataframes to include only variables I’ll need for the analysis, like dbn schoolname schooltype
Safety and Respect score based on parent responses Communication score based on parent responses Engagement score based on parent responses Academic expectations score based on parent responses Safety and Respect score based on teacher responses Communication score based on teacher responses Engagement score based on teacher responses Academic expectations score based on teacher responses Safety and Respect score based on student responses Communication score based on student responses Engagement score based on student responses Academic expectations score based on student responses Safety and Respect total score Communication total score Engagement total score Academic Expectations total score

survey_data_dis <- survey_data_dis %>% select(dbn,schoolname,schooltype,saf_p_11,com_p_11,eng_p_11,aca_p_11,saf_t_11,com_t_11,eng_t_11,aca_t_11,saf_s_11,com_s_11,  
eng_s_11,aca_s_11,saf_tot_11,com_tot_11,eng_tot_11,aca_tot_11) %>% filter(schooltype == "District 75 Special Education")
survey_data_dis

Creating a Single DataFrame for Analysis

survey_data <- survey_data_gen %>% bind_rows(survey_data_dis)
survey_data

Since bind_rows(), like other dplyr functions, is designed for manipulating dataframes, it can be used in situations where dataframes have different numbers of variable columns. Using bind_rows() here, the output dataframe will contain a column if that column appears in any of the input dataframes,I’m using bind_rows() to combine "survey_data_gen and survey_data_dis into a single dataframe

survey_combined <- combined %>% left_join(survey_data, by = "dbn")
survey_combined

What determined the type of join I use?

it makes sense to join the survey data to combined using left_join(), which will retain only observations in the survey_combined dataframe that correspond to observations in combined.

Look for Interesting Correlations and Examine Relationships Using Scatter Plots

Finding the correlation coefficient showing the parent, teacher and student perceptions of the following factors and how they affect average school SAT scores(an indicator of academic performance):

  1. Safety
  2. Engagement
  3. Communication
  4. Academics
colSums(is.na(survey_combined))
                                 dbn                          school_name 
                                   0                                    0 
              num_of_sat_test_takers       sat_critical_reading_avg_score 
                                  57                                   57 
                  sat_math_avg_score                sat_writing_avg_score 
                                  57                                   57 
                       avg_sat_score                       ap_test_takers 
                                  57                                    0 
                   total_exams_taken number_of_exams_with_scores_3_4_or_5 
                                 247                                  328 
                   exams_per_student                   high_score_percent 
                                 247                                  328 
                      avg_class_size                          frl_percent 
                                  44                                   41 
                    total_enrollment                          ell_percent 
                                  41                                   41 
                        sped_percent                    selfcontained_num 
                                  41                                   51 
                           asian_per                            black_per 
                                  41                                   41 
                        hispanic_per                            white_per 
                                  41                                   41 
                            male_per                           female_per 
                                  41                                   41 
                        total_cohort                        grads_percent 
                                  89                                  111 
                     dropout_percent                                 boro 
                                 111                                  109 
                                 lat                                 long 
                                 109                                  109 
                            location                           schoolname 
                                 109                                  105 
                          schooltype                             saf_p_11 
                                 105                                  105 
                            com_p_11                             eng_p_11 
                                 105                                  105 
                            aca_p_11                             saf_t_11 
                                 105                                  105 
                            com_t_11                             eng_t_11 
                                 105                                  105 
                            aca_t_11                             saf_s_11 
                                 105                                  107 
                            com_s_11                             eng_s_11 
                                 107                                  107 
                            aca_s_11                           saf_tot_11 
                                 107                                  105 
                          com_tot_11                           eng_tot_11 
                                 105                                  105 
                          aca_tot_11 
                                 105 

How do I handle missing values?

Using use = “pairwise.complete.obs” , when this is used we discard the entire row if an NA is present, and use the non-NA values when calculating correlation

survey_mat <- survey_combined %>% select(avg_sat_score,saf_p_11:aca_tot_11) %>% cor(use = "pairwise.complete.obs")
survey_tib <- survey_mat %>% as_tibble(rownames = "variable")
cor_s <- survey_tib %>% select(variable,avg_sat_score) %>% filter(avg_sat_score >0.25 | avg_sat_score< - 0.25)
cor_s

I created a correlation matrix to look for interesting relationship between the pair of variables in the new combined dataframe

“The closer correlation coefficient is to zero the weaker the relationship”, with this I can say that there is a weak positive relationship between saf_t_11, saf_s_11, aca_s_11, saf_tot_11 and avg_sat_score

create_scatter <- function(x,y){
  ggplot(data = survey_combined, aes_string(x = x , y = y))+geom_point()
}

y = names(survey_combined)[7]
x = c("saf_t_11","saf_s_11", "aca_s_11", "saf_tot_11")

comparison <- map2(x,y,create_scatter)
comparison
[[1]]

[[2]]

[[3]]

[[4]]

“You can tell a relationship is positive if values of variable 1 increase so do values of variable 2” The points are spread out indicating a weak positive relationship. I can point out that safety and respect score and the avg_sat_score contribute to each other but the connection is weak. The more safe the environment the more comfortable the student,parent, teacher feel

Differences in Student, Parent and Teacher Percep tions

Using the function pivot_longer to reshape the dataframe

survey_combined_r <- survey_combined %>% pivot_longer(cols = c(saf_p_11:aca_tot_11 ), names_to = "survey_question", values_to = "score")

survey_combined_r
NA

Creating a new variable to extract information from the values of the survey question

survey_combined_r <- survey_combined_r %>% mutate(response_type = str_sub(survey_question, 4,6))
survey_combined_r <- survey_combined_r %>% mutate(metric = str_sub(survey_question,1,3))

We can use if_else() to assign more intuitive value names to the variables

combined_survey_gather <- survey_combined_r %>% mutate(response_type = ifelse(response_type == "_p_","parent",  ifelse(response_type == "_t_","teacher",ifelse(response_type == "_s_","student",ifelse(response_type == "_to","total","NA")))))
combined_survey_gather

for the metrics

combined_survey_gather <- combined_survey_gather %>% mutate(metric = ifelse(metric =="saf", "safety and respect", ifelse(metric == "com","communication",ifelse(metric == "eng","engagement",ifelse(metric == "aca","academic expectation","NA")))))
combined_survey_gather

creating a summary summaryusing the NYC quality metrics

´

summary <- combined_survey_gather %>% filter(response_type != "total") 
 ggplot(data = summary, aes(x = metric , y = score , color = response_type))+geom_boxplot()+theme(

panel.background = element_rect(fill = "white"))

  1. Comparing the median; Looking at the plot the parent’s perception to the survey questions were higher than the student’s and teacher’s response, same as n the communication and engagement perceptions , The parent feel a lot more optimistic about how safe the schools are than the students and teachers. Also I noticed that the student perceptions were lower on all survey responses

Teachers and Student academic perceptions were lower but not too far from the parent’s academic perceptions

  1. Comparison of dispersion; "The longer the box the more dispersed the data. The smaller the less dispersed the data. As we can see the teacher box plot is much more dispersed than both the student and parent plot, the teachers perceptions were not in agreement with the parents and students responses.

  2. Comparison of Outliners; The parent had relatively high value to the response to the survey while the teachers had a low value


survey_mat_gen <- survey_combined %>% select(male_per:female_per, sat_critical_reading_avg_score: avg_sat_score) %>% cor(use = "pairwise.complete.obs")
survey_tib_gen <- survey_mat_gen %>% as_tibble(rownames = "variable")
cor_s_gen <- survey_tib_gen %>% select(variable,male_per:female_per) 
cor_s_gen

Is there any relationship between gender percentage and average SAT score? There’s almost no correlation between the gender percentage and average SAT score

combined_survey_gather
school_metrics <- combined_survey_gather %>% filter(response_type != "total") %>% drop_na(score) %>% select(school_name,response_type,score) %>% group_by(school_name) %>% summarise( mean = mean(score))
`summarise()` ungrouping output (override with `.groups` argument)
school_metrics  %>% arrange(-mean)

These are the school with the best quality metrics URBAN ACADEMY LABORATORY HIGH SCHOOL
CROTONA ACADEMY HIGH SCHOOL HIGH SCHOOL X560 s BRONX ACADEMY HIGH SCHOOL
BROWNSVILLE ACADEMY HIGH SCHOOL VOYAGES PREPARATORY THE CINEMA SCHOOL

if I break it down by response type

combined_survey_gather
school_metrics <- combined_survey_gather %>% filter(response_type != "total") %>% drop_na(score) %>% select(school_name,response_type,score) %>% group_by(response_type) %>% summarise( mean = mean(score))
`summarise()` ungrouping output (override with `.groups` argument)
school_metrics  %>% arrange(-mean)

if broken down by response type , the parents has the best quality metrics, followed by the teacher and student

survey_diff <- survey_combined %>% mutate(diff_saf = saf_s_11 - saf_p_11)
survey_diff
survey_mat_diff <- survey_diff %>% select_if(is.numeric) %>% select(!contains("_11")) %>% cor(use = "pairwise.complete.obs")
survey_tib_diff <- survey_mat_diff %>% as_tibble(rownames = "variable")
cor_s_diff <- survey_tib_diff %>% select(variable,diff_saf) %>% filter(diff_saf>0.25 | diff_saf < - 0.25)
cor_s_diff

One noticeable thing is that there is a negative correlation between black_per and diff_saf. This means that black population feels less safe also there’s a negative correlation between the sped_percent and diff_saf the student participating in special education also feel less safe , due to so many reasons

LS0tDQp0aXRsZTogIkd1aWRlZCBQcm9qZWN0OiBFeHBsb3JpbmcgTllDIFNjaG9vbHMgU3VydmV5IERhdGEiDQphdXRob3I6ICJUb3NpbiBPYmFsYW5hIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KSW4gdGhpcyBwcm9qZWN0LCBJIHdpbGwgYW5hbHl6ZSBkYXRhIGZyb20gdGhlIE5ldyBZb3JrIENpdHkgc2Nob29sIGRlcGFydG1lbnQgdG8gdW5kZXJzdGFuZCB3aGV0aGVyIHBhcmVudCwgdGVhY2hlciBhbmQgc3R1ZGVudCBwZXJjZXB0aW9ucyBvZiB0aGUgZm9sbG93aW5nIGZhY3RvcnMgYWZmZWN0IGF2ZXJhZ2Ugc2Nob29sIFNBVCBzY29yZXMoYW4gaW5kaWNhdG9yIG9mIGFjYWRlbWljIHBlcmZvcm1hbmNlKToNCg0KMS4gU2FmZXR5DQoyLiBFbmdhZ2VtZW50DQozLiBDb21tdW5pY2F0aW9uDQo0LiBBY2FkZW1pY3MNCg0KSSdsbCBzdGFydCBieSBpbnN0YWxsaW5nIHRoZSBwYWNrYWdlcyBuZWVkZWQgZm9yIHRoaXMgYW5hbHlzaXMNCg0KYGBge3J9DQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShyZWFkeGwpDQpgYGANCg0KSW4gdGhpcyBwcm9qZWN0LCB3ZSdsbCBiZSBpbnZlc3RpZ2F0aW5nIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOlwNCjEuIERvIHN0dWRlbnQsIHRlYWNoZXIsIGFuZCBwYXJlbnQgcGVyY2VwdGlvbnMgb2YgTllDIHNjaG9vbCBxdWFsaXR5IGFwcGVhciB0byBiZSByZWxhdGVkIHRvIGRlbW9ncmFwaGljIGFuZCBhY2FkZW1pYyBzdWNjZXNzIG1ldHJpY3M/DQoyLiBEbyBzdHVkZW50cywgdGVhY2hlcnMsIGFuZCBwYXJlbnRzIGhhdmUgc2ltaWxhciBwZXJjZXB0aW9ucyBvZiBOWUMgc2Nob29sIHF1YWxpdHk/DQoNCg0KSW1wb3J0aW5nIERhdGENCg0KYGBge3J9DQpzdXJ2ZXlfZGljdCA8LSByZWFkX3hscygiU3VydmV5IERhdGEgRGljdGlvbmFyeS54bHMiKQ0Kc3VydmV5X2RpY3QNCmBgYA0KU3VydmV5IERhdGEgRGljdGlvbmFyeS54bHMsIGNvbnRhaW5zIG1ldGFkYXRhIHRoYXQgd2lsbCBiZSB1c2VmdWwgdG8gZGVjaWRlIGhvdyB0byBjbGVhbiBhbmQgcHJlcGFyZSB0aGUgc3VydmV5IGRhdGEgZm9yIGFuYWx5c2lzLg0KDQpgYGB7cn0NCnN1cnZleV9kYXRhX2dlbiA8LSByZWFkX3RzdigibWFzdGVyZmlsZTExX2dlbmVkX2ZpbmFsLnR4dCIpDQpzdXJ2ZXlfZGF0YV9nZW4NCmBgYA0KDQpUaGUgbWFzdGVyZmlsZTExX2dlbmVkX2ZpbmFsLnR4dCBmaWxlLCBjb250YWluIHN1cnZleSBkYXRhIGZvciAiZ2VuZXJhbCBlZHVjYXRpb24iIHNjaG9vbHMg4oCUIHRob3NlIHRoYXQgZG8gbm90IHNwZWNpZmljYWxseSBzZXJ2ZSBwb3B1bGF0aW9ucyB3aXRoIHNwZWNpYWwgbmVlZHMuDQoNCmBgYHtyfQ0Kc3VydmV5X2RhdGFfZGlzIDwtIHJlYWRfdHN2KCJtYXN0ZXJmaWxlMTFfZDc1X2ZpbmFsLnR4dCIpDQpzdXJ2ZXlfZGF0YV9kaXMNCmBgYA0KDQpUaGUgbWFzdGVyZmlsZTExX2Q3NV9maW5hbC50eHQgZmlsZSBjb250YWluIHN1cnZleSBkYXRhIGZvciBEaXN0cmljdCA3NSBzY2hvb2xzLCB3aGljaCBwcm92aWRlIHNwZWNpYWwgZWR1Y2F0aW9uIHN1cHBvcnQgZm9yIGNoaWxkcmVuIHdpdGggc3BlY2lhbCBuZWVkcyBzdWNoIGFzIGxlYXJuaW5nIG9yIHBoeXNpY2FsIGRpc2FiaWxpdGllcy4NCg0KYGBge3J9DQpjb21iaW5lZCA8LSByZWFkX2NzdigiY29tYmluZWQuY3N2IikNCmNvbWJpbmVkDQpgYGANCiMgU2ltcGxpZnlpbmcgRGF0YUZyYW1lcw0KYGBge3J9DQpzdXJ2ZXlfZGF0YV9nZW4gPC0gc3VydmV5X2RhdGFfZ2VuICU+JSBzZWxlY3QoZGJuLHNjaG9vbG5hbWUsc2Nob29sdHlwZSxzYWZfcF8xMSxjb21fcF8xMSxlbmdfcF8xMSxhY2FfcF8xMSxzYWZfdF8xMSxjb21fdF8xMSxlbmdfdF8xMSxhY2FfdF8xMSxzYWZfc18xMSxjb21fc18xMSwJDQplbmdfc18xMSxhY2Ffc18xMSxzYWZfdG90XzExLGNvbV90b3RfMTEsZW5nX3RvdF8xMSxhY2FfdG90XzExKSAlPiUgZmlsdGVyKHNjaG9vbHR5cGUgPT0gIkhpZ2ggU2Nob29sIikNCnN1cnZleV9kYXRhX2dlbg0KYGBgDQpJJ20gc2ltcGxpZnlpbmcgZGF0YWZyYW1lcyB0byBpbmNsdWRlIG9ubHkgdmFyaWFibGVzIEknbGwgbmVlZCBmb3IgdGhlIGFuYWx5c2lzLCBsaWtlIA0KZGJuIA0Kc2Nob29sbmFtZSANCnNjaG9vbHR5cGUgCQ0KU2FmZXR5IGFuZCBSZXNwZWN0IHNjb3JlIGJhc2VkIG9uIHBhcmVudCByZXNwb25zZXMNCkNvbW11bmljYXRpb24gc2NvcmUgYmFzZWQgb24gcGFyZW50IHJlc3BvbnNlcw0KRW5nYWdlbWVudCBzY29yZSBiYXNlZCBvbiBwYXJlbnQgcmVzcG9uc2VzDQpBY2FkZW1pYyBleHBlY3RhdGlvbnMgc2NvcmUgYmFzZWQgb24gcGFyZW50IHJlc3BvbnNlcw0KU2FmZXR5IGFuZCBSZXNwZWN0IHNjb3JlIGJhc2VkIG9uIHRlYWNoZXIgcmVzcG9uc2VzDQpDb21tdW5pY2F0aW9uIHNjb3JlIGJhc2VkIG9uIHRlYWNoZXIgcmVzcG9uc2VzDQpFbmdhZ2VtZW50IHNjb3JlIGJhc2VkIG9uIHRlYWNoZXIgcmVzcG9uc2VzDQpBY2FkZW1pYyBleHBlY3RhdGlvbnMgc2NvcmUgYmFzZWQgb24gdGVhY2hlciByZXNwb25zZXMNClNhZmV0eSBhbmQgUmVzcGVjdCBzY29yZSBiYXNlZCBvbiBzdHVkZW50IHJlc3BvbnNlcw0KQ29tbXVuaWNhdGlvbiBzY29yZSBiYXNlZCBvbiBzdHVkZW50IHJlc3BvbnNlcw0KRW5nYWdlbWVudCBzY29yZSBiYXNlZCBvbiBzdHVkZW50IHJlc3BvbnNlcw0KQWNhZGVtaWMgZXhwZWN0YXRpb25zIHNjb3JlIGJhc2VkIG9uIHN0dWRlbnQgcmVzcG9uc2VzDQpTYWZldHkgYW5kIFJlc3BlY3QgdG90YWwgc2NvcmUNCkNvbW11bmljYXRpb24gdG90YWwgc2NvcmUNCkVuZ2FnZW1lbnQgdG90YWwgc2NvcmUNCkFjYWRlbWljIEV4cGVjdGF0aW9ucyB0b3RhbCBzY29yZQ0KDQpgYGB7cn0NCnN1cnZleV9kYXRhX2RpcyA8LSBzdXJ2ZXlfZGF0YV9kaXMgJT4lIHNlbGVjdChkYm4sc2Nob29sbmFtZSxzY2hvb2x0eXBlLHNhZl9wXzExLGNvbV9wXzExLGVuZ19wXzExLGFjYV9wXzExLHNhZl90XzExLGNvbV90XzExLGVuZ190XzExLGFjYV90XzExLHNhZl9zXzExLGNvbV9zXzExLAkNCmVuZ19zXzExLGFjYV9zXzExLHNhZl90b3RfMTEsY29tX3RvdF8xMSxlbmdfdG90XzExLGFjYV90b3RfMTEpICU+JSBmaWx0ZXIoc2Nob29sdHlwZSA9PSAiRGlzdHJpY3QgNzUgU3BlY2lhbCBFZHVjYXRpb24iKQ0Kc3VydmV5X2RhdGFfZGlzDQpgYGANCiMgQ3JlYXRpbmcgYSBTaW5nbGUgRGF0YUZyYW1lIGZvciBBbmFseXNpcw0KYGBge3J9DQpzdXJ2ZXlfZGF0YSA8LSBzdXJ2ZXlfZGF0YV9nZW4gJT4lIGJpbmRfcm93cyhzdXJ2ZXlfZGF0YV9kaXMpDQpzdXJ2ZXlfZGF0YQ0KYGBgDQpTaW5jZSBiaW5kX3Jvd3MoKSwgbGlrZSBvdGhlciBkcGx5ciBmdW5jdGlvbnMsIGlzIGRlc2lnbmVkIGZvciBtYW5pcHVsYXRpbmcgZGF0YWZyYW1lcywgaXQgY2FuIGJlIHVzZWQgaW4gc2l0dWF0aW9ucyB3aGVyZSBkYXRhZnJhbWVzIGhhdmUgZGlmZmVyZW50IG51bWJlcnMgb2YgdmFyaWFibGUgY29sdW1ucy4gVXNpbmcgYmluZF9yb3dzKCkgaGVyZSwgdGhlIG91dHB1dCBkYXRhZnJhbWUgd2lsbCBjb250YWluIGEgY29sdW1uIGlmIHRoYXQgY29sdW1uIGFwcGVhcnMgaW4gYW55IG9mIHRoZSBpbnB1dCBkYXRhZnJhbWVzLEknbSB1c2luZyBiaW5kX3Jvd3MoKSB0byBjb21iaW5lICJzdXJ2ZXlfZGF0YV9nZW4gYW5kIHN1cnZleV9kYXRhX2RpcyBpbnRvIGEgc2luZ2xlIGRhdGFmcmFtZQ0KDQpgYGB7cn0NCnN1cnZleV9jb21iaW5lZCA8LSBjb21iaW5lZCAlPiUgbGVmdF9qb2luKHN1cnZleV9kYXRhLCBieSA9ICJkYm4iKQ0Kc3VydmV5X2NvbWJpbmVkDQpgYGANCg0KV2hhdCBkZXRlcm1pbmVkIHRoZSB0eXBlIG9mIGpvaW4gSSB1c2U/DQoNCml0IG1ha2VzIHNlbnNlIHRvIGpvaW4gdGhlIHN1cnZleSBkYXRhIHRvIGNvbWJpbmVkIHVzaW5nIGxlZnRfam9pbigpLCB3aGljaCB3aWxsIHJldGFpbiBvbmx5IG9ic2VydmF0aW9ucyBpbiB0aGUgc3VydmV5X2NvbWJpbmVkIGRhdGFmcmFtZSB0aGF0IGNvcnJlc3BvbmQgdG8gb2JzZXJ2YXRpb25zIGluIGNvbWJpbmVkLg0KDQoNCiMgTG9vayBmb3IgSW50ZXJlc3RpbmcgQ29ycmVsYXRpb25zIGFuZCBFeGFtaW5lIFJlbGF0aW9uc2hpcHMgVXNpbmcgU2NhdHRlciBQbG90cw0KDQpGaW5kaW5nIHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBzaG93aW5nIHRoZSBwYXJlbnQsIHRlYWNoZXIgYW5kIHN0dWRlbnQgcGVyY2VwdGlvbnMgb2YgdGhlIGZvbGxvd2luZyBmYWN0b3JzIGFuZCBob3cgdGhleSBhZmZlY3QgYXZlcmFnZSBzY2hvb2wgU0FUIHNjb3JlcyhhbiBpbmRpY2F0b3Igb2YgYWNhZGVtaWMgcGVyZm9ybWFuY2UpOg0KDQoxLiBTYWZldHkNCjIuIEVuZ2FnZW1lbnQNCjMuIENvbW11bmljYXRpb24NCjQuIEFjYWRlbWljcw0KDQpgYGB7cn0NCmNvbFN1bXMoaXMubmEoc3VydmV5X2NvbWJpbmVkKSkNCmBgYA0KSG93IGRvIEkgaGFuZGxlIG1pc3NpbmcgdmFsdWVzPw0KDQpVc2luZyB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiAsIHdoZW4gdGhpcyBpcyB1c2VkIHdlIGRpc2NhcmQgdGhlIGVudGlyZSByb3cgaWYgYW4gTkEgIGlzIHByZXNlbnQsIGFuZCB1c2UgdGhlIG5vbi1OQSB2YWx1ZXMgd2hlbiBjYWxjdWxhdGluZyBjb3JyZWxhdGlvbiANCg0KDQpgYGB7cn0NCnN1cnZleV9tYXQgPC0gc3VydmV5X2NvbWJpbmVkICU+JSBzZWxlY3QoYXZnX3NhdF9zY29yZSxzYWZfcF8xMTphY2FfdG90XzExKSAlPiUgY29yKHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQ0Kc3VydmV5X3RpYiA8LSBzdXJ2ZXlfbWF0ICU+JSBhc190aWJibGUocm93bmFtZXMgPSAidmFyaWFibGUiKQ0KY29yX3MgPC0gc3VydmV5X3RpYiAlPiUgc2VsZWN0KHZhcmlhYmxlLGF2Z19zYXRfc2NvcmUpICU+JSBmaWx0ZXIoYXZnX3NhdF9zY29yZSA+MC4yNSB8IGF2Z19zYXRfc2NvcmU8IC0gMC4yNSkNCmNvcl9zDQpgYGANCg0KSSBjcmVhdGVkIGEgY29ycmVsYXRpb24gbWF0cml4IHRvIGxvb2sgZm9yIGludGVyZXN0aW5nIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBwYWlyIG9mIHZhcmlhYmxlcyBpbiB0aGUgbmV3IGNvbWJpbmVkIGRhdGFmcmFtZSANCg0KIlRoZSBjbG9zZXIgY29ycmVsYXRpb24gY29lZmZpY2llbnQgaXMgdG8gemVybyB0aGUgd2Vha2VyIHRoZSByZWxhdGlvbnNoaXAiLCB3aXRoIHRoaXMgSSBjYW4gc2F5IHRoYXQgdGhlcmUgaXMgYSB3ZWFrIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNhZl90XzExLCBzYWZfc18xMSwgYWNhX3NfMTEsIHNhZl90b3RfMTEgYW5kIGF2Z19zYXRfc2NvcmUgDQoNCg0KYGBge3J9DQpjcmVhdGVfc2NhdHRlciA8LSBmdW5jdGlvbih4LHkpew0KICBnZ3Bsb3QoZGF0YSA9IHN1cnZleV9jb21iaW5lZCwgYWVzX3N0cmluZyh4ID0geCAsIHkgPSB5KSkrZ2VvbV9wb2ludCgpDQp9DQoNCnkgPSBuYW1lcyhzdXJ2ZXlfY29tYmluZWQpWzddDQp4ID0gYygic2FmX3RfMTEiLCJzYWZfc18xMSIsICJhY2Ffc18xMSIsICJzYWZfdG90XzExIikNCg0KY29tcGFyaXNvbiA8LSBtYXAyKHgseSxjcmVhdGVfc2NhdHRlcikNCmNvbXBhcmlzb24NCmBgYA0KIllvdSBjYW4gdGVsbCBhIHJlbGF0aW9uc2hpcCBpcyBwb3NpdGl2ZSBpZiB2YWx1ZXMgb2YgdmFyaWFibGUgMSBpbmNyZWFzZSBzbyBkbyB2YWx1ZXMgb2YgdmFyaWFibGUgMiIgDQpUaGUgcG9pbnRzIGFyZSBzcHJlYWQgb3V0IGluZGljYXRpbmcgYSB3ZWFrIHBvc2l0aXZlIHJlbGF0aW9uc2hpcC4gSSBjYW4gcG9pbnQgb3V0IHRoYXQgc2FmZXR5IGFuZCByZXNwZWN0IHNjb3JlIGFuZCB0aGUgYXZnX3NhdF9zY29yZSBjb250cmlidXRlIHRvIGVhY2ggb3RoZXIgYnV0IHRoZSBjb25uZWN0aW9uIGlzIHdlYWsuIFRoZSBtb3JlIHNhZmUgdGhlIGVudmlyb25tZW50IHRoZSBtb3JlIGNvbWZvcnRhYmxlIHRoZSBzdHVkZW50LHBhcmVudCwgdGVhY2hlciBmZWVsDQoNCg0KIyBEaWZmZXJlbmNlcyBpbiBTdHVkZW50LCBQYXJlbnQgYW5kIFRlYWNoZXIgUGVyY2VwIHRpb25zDQoNClVzaW5nIHRoZSBmdW5jdGlvbiBwaXZvdF9sb25nZXIgdG8gcmVzaGFwZSB0aGUgZGF0YWZyYW1lDQoNCmBgYHtyfQ0Kc3VydmV5X2NvbWJpbmVkX3IgPC0gc3VydmV5X2NvbWJpbmVkICU+JSBwaXZvdF9sb25nZXIoY29scyA9IGMoc2FmX3BfMTE6YWNhX3RvdF8xMSApLCBuYW1lc190byA9ICJzdXJ2ZXlfcXVlc3Rpb24iLCB2YWx1ZXNfdG8gPSAic2NvcmUiKQ0KDQpzdXJ2ZXlfY29tYmluZWRfcg0KDQpgYGANCkNyZWF0aW5nIGEgbmV3IHZhcmlhYmxlIHRvIGV4dHJhY3QgaW5mb3JtYXRpb24gZnJvbSB0aGUgdmFsdWVzIG9mIHRoZSBzdXJ2ZXkgcXVlc3Rpb24NCg0KYGBge3J9DQpzdXJ2ZXlfY29tYmluZWRfciA8LSBzdXJ2ZXlfY29tYmluZWRfciAlPiUgbXV0YXRlKHJlc3BvbnNlX3R5cGUgPSBzdHJfc3ViKHN1cnZleV9xdWVzdGlvbiwgNCw2KSkNCnN1cnZleV9jb21iaW5lZF9yIDwtIHN1cnZleV9jb21iaW5lZF9yICU+JSBtdXRhdGUobWV0cmljID0gc3RyX3N1YihzdXJ2ZXlfcXVlc3Rpb24sMSwzKSkNCmBgYA0KDQpXZSBjYW4gdXNlIGlmX2Vsc2UoKSB0byBhc3NpZ24gbW9yZSBpbnR1aXRpdmUgdmFsdWUgbmFtZXMgdG8gdGhlIHZhcmlhYmxlcw0KDQpgYGB7cn0NCmNvbWJpbmVkX3N1cnZleV9nYXRoZXIgPC0gc3VydmV5X2NvbWJpbmVkX3IgJT4lIG11dGF0ZShyZXNwb25zZV90eXBlID0gaWZlbHNlKHJlc3BvbnNlX3R5cGUgPT0gIl9wXyIsInBhcmVudCIsICBpZmVsc2UocmVzcG9uc2VfdHlwZSA9PSAiX3RfIiwidGVhY2hlciIsaWZlbHNlKHJlc3BvbnNlX3R5cGUgPT0gIl9zXyIsInN0dWRlbnQiLGlmZWxzZShyZXNwb25zZV90eXBlID09ICJfdG8iLCJ0b3RhbCIsIk5BIikpKSkpDQpjb21iaW5lZF9zdXJ2ZXlfZ2F0aGVyDQpgYGANCmZvciB0aGUgbWV0cmljcw0KDQpgYGB7cn0NCmNvbWJpbmVkX3N1cnZleV9nYXRoZXIgPC0gY29tYmluZWRfc3VydmV5X2dhdGhlciAlPiUgbXV0YXRlKG1ldHJpYyA9IGlmZWxzZShtZXRyaWMgPT0ic2FmIiwgInNhZmV0eSBhbmQgcmVzcGVjdCIsIGlmZWxzZShtZXRyaWMgPT0gImNvbSIsImNvbW11bmljYXRpb24iLGlmZWxzZShtZXRyaWMgPT0gImVuZyIsImVuZ2FnZW1lbnQiLGlmZWxzZShtZXRyaWMgPT0gImFjYSIsImFjYWRlbWljIGV4cGVjdGF0aW9uIiwiTkEiKSkpKSkNCmNvbWJpbmVkX3N1cnZleV9nYXRoZXINCmBgYA0KY3JlYXRpbmcgYSBzdW1tYXJ5IHN1bW1hcnl1c2luZyB0aGUgTllDIHF1YWxpdHkgbWV0cmljcw0KDQrCtA0KYGBge3J9DQpzdW1tYXJ5IDwtIGNvbWJpbmVkX3N1cnZleV9nYXRoZXIgJT4lIGZpbHRlcihyZXNwb25zZV90eXBlICE9ICJ0b3RhbCIpIA0KIGdncGxvdChkYXRhID0gc3VtbWFyeSwgYWVzKHggPSBtZXRyaWMgLCB5ID0gc2NvcmUgLCBjb2xvciA9IHJlc3BvbnNlX3R5cGUpKStnZW9tX2JveHBsb3QoKSt0aGVtZSgNCg0KcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpDQpgYGANCjEuIENvbXBhcmluZyB0aGUgbWVkaWFuOyBMb29raW5nIGF0IHRoZSBwbG90IHRoZSBwYXJlbnQncyBwZXJjZXB0aW9uIHRvIHRoZSBzdXJ2ZXkgcXVlc3Rpb25zIHdlcmUgaGlnaGVyIHRoYW4gdGhlIHN0dWRlbnQncyBhbmQgdGVhY2hlcidzIHJlc3BvbnNlLCBzYW1lIGFzIG4gdGhlIGNvbW11bmljYXRpb24gYW5kIGVuZ2FnZW1lbnQgcGVyY2VwdGlvbnMgICwgVGhlIHBhcmVudCBmZWVsIGEgbG90IG1vcmUgb3B0aW1pc3RpYyBhYm91dCBob3cgc2FmZSB0aGUgc2Nob29scyBhcmUgdGhhbiB0aGUgc3R1ZGVudHMgYW5kIHRlYWNoZXJzLiBBbHNvIEkgbm90aWNlZCB0aGF0IHRoZSBzdHVkZW50IHBlcmNlcHRpb25zIHdlcmUgbG93ZXIgb24gYWxsIHN1cnZleSByZXNwb25zZXMNCg0KVGVhY2hlcnMgYW5kIFN0dWRlbnQgYWNhZGVtaWMgcGVyY2VwdGlvbnMgd2VyZSBsb3dlciBidXQgbm90IHRvbyBmYXIgZnJvbSB0aGUgcGFyZW50J3MgYWNhZGVtaWMgcGVyY2VwdGlvbnMNCg0KMi4gQ29tcGFyaXNvbiBvZiBkaXNwZXJzaW9uOyAgIlRoZSBsb25nZXIgdGhlIGJveCB0aGUgbW9yZSBkaXNwZXJzZWQgdGhlIGRhdGEuIFRoZSBzbWFsbGVyIHRoZSBsZXNzIGRpc3BlcnNlZCB0aGUgZGF0YS4gIEFzIHdlIGNhbiBzZWUgdGhlIHRlYWNoZXIgYm94IHBsb3QgaXMgbXVjaCBtb3JlIGRpc3BlcnNlZCB0aGFuIGJvdGggdGhlIHN0dWRlbnQgYW5kIHBhcmVudCBwbG90LCB0aGUgdGVhY2hlcnMgcGVyY2VwdGlvbnMgd2VyZSBub3QgaW4gYWdyZWVtZW50IHdpdGggdGhlIHBhcmVudHMgYW5kIHN0dWRlbnRzIHJlc3BvbnNlcy4gDQogDQozLiBDb21wYXJpc29uIG9mIE91dGxpbmVyczsgVGhlIHBhcmVudCBoYWQgcmVsYXRpdmVseSBoaWdoIHZhbHVlIHRvIHRoZSByZXNwb25zZSB0byB0aGUgc3VydmV5IHdoaWxlIHRoZSB0ZWFjaGVycyBoYWQgYSBsb3cgdmFsdWUgDQoNCg0KYGBge3J9DQoNCnN1cnZleV9tYXRfZ2VuIDwtIHN1cnZleV9jb21iaW5lZCAlPiUgc2VsZWN0KG1hbGVfcGVyOmZlbWFsZV9wZXIsIHNhdF9jcml0aWNhbF9yZWFkaW5nX2F2Z19zY29yZTogYXZnX3NhdF9zY29yZSkgJT4lIGNvcih1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikNCnN1cnZleV90aWJfZ2VuIDwtIHN1cnZleV9tYXRfZ2VuICU+JSBhc190aWJibGUocm93bmFtZXMgPSAidmFyaWFibGUiKQ0KY29yX3NfZ2VuIDwtIHN1cnZleV90aWJfZ2VuICU+JSBzZWxlY3QodmFyaWFibGUsbWFsZV9wZXI6ZmVtYWxlX3BlcikgDQpjb3Jfc19nZW4NCmBgYA0KSXMgdGhlcmUgYW55IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGdlbmRlciBwZXJjZW50YWdlIGFuZCBhdmVyYWdlIFNBVCBzY29yZT8NClRoZXJlJ3MgYWxtb3N0IG5vIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGdlbmRlciBwZXJjZW50YWdlIGFuZCBhdmVyYWdlIFNBVCBzY29yZQ0KDQpgYGB7cn0NCmNvbWJpbmVkX3N1cnZleV9nYXRoZXINCnNjaG9vbF9tZXRyaWNzIDwtIGNvbWJpbmVkX3N1cnZleV9nYXRoZXIgJT4lIGZpbHRlcihyZXNwb25zZV90eXBlICE9ICJ0b3RhbCIpICU+JSBkcm9wX25hKHNjb3JlKSAlPiUgc2VsZWN0KHNjaG9vbF9uYW1lLHJlc3BvbnNlX3R5cGUsc2NvcmUpICU+JSBncm91cF9ieShzY2hvb2xfbmFtZSkgJT4lIHN1bW1hcmlzZSggbWVhbiA9IG1lYW4oc2NvcmUpKQ0Kc2Nob29sX21ldHJpY3MgICU+JSBhcnJhbmdlKC1tZWFuKQ0KYGBgDQpUaGVzZSBhcmUgdGhlIHNjaG9vbCB3aXRoIHRoZSBiZXN0IHF1YWxpdHkgbWV0cmljcw0KVVJCQU4gQUNBREVNWSBMQUJPUkFUT1JZIEhJR0ggU0NIT09MCQ0KQ1JPVE9OQSBBQ0FERU1ZIEhJR0ggU0NIT09MDQpISUdIIFNDSE9PTCBYNTYwIHMgQlJPTlggQUNBREVNWSBISUdIIFNDSE9PTAkNCkJST1dOU1ZJTExFIEFDQURFTVkgSElHSCBTQ0hPT0wJDQpWT1lBR0VTIFBSRVBBUkFUT1JZCQ0KVEhFIENJTkVNQSBTQ0hPT0wNCg0KaWYgSSBicmVhayBpdCBkb3duIGJ5IHJlc3BvbnNlIHR5cGUgDQoNCmBgYHtyfQ0KY29tYmluZWRfc3VydmV5X2dhdGhlcg0Kc2Nob29sX21ldHJpY3MgPC0gY29tYmluZWRfc3VydmV5X2dhdGhlciAlPiUgZmlsdGVyKHJlc3BvbnNlX3R5cGUgIT0gInRvdGFsIikgJT4lIGRyb3BfbmEoc2NvcmUpICU+JSBzZWxlY3Qoc2Nob29sX25hbWUscmVzcG9uc2VfdHlwZSxzY29yZSkgJT4lIGdyb3VwX2J5KHJlc3BvbnNlX3R5cGUpICU+JSBzdW1tYXJpc2UoIG1lYW4gPSBtZWFuKHNjb3JlKSkNCnNjaG9vbF9tZXRyaWNzICAlPiUgYXJyYW5nZSgtbWVhbikNCmBgYA0KDQppZiBicm9rZW4gZG93biBieSByZXNwb25zZSB0eXBlICwgdGhlIHBhcmVudHMgaGFzIHRoZSBiZXN0IHF1YWxpdHkgbWV0cmljcywgZm9sbG93ZWQgYnkgdGhlIHRlYWNoZXIgYW5kIHN0dWRlbnQNCg0KYGBge3J9DQpzdXJ2ZXlfZGlmZiA8LSBzdXJ2ZXlfY29tYmluZWQgJT4lIG11dGF0ZShkaWZmX3NhZiA9IHNhZl9zXzExIC0gc2FmX3BfMTEpDQpzdXJ2ZXlfZGlmZg0KYGBgDQoNCmBgYHtyfQ0Kc3VydmV5X21hdF9kaWZmIDwtIHN1cnZleV9kaWZmICU+JSBzZWxlY3RfaWYoaXMubnVtZXJpYykgJT4lIHNlbGVjdCghY29udGFpbnMoIl8xMSIpKSAlPiUgY29yKHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQ0Kc3VydmV5X3RpYl9kaWZmIDwtIHN1cnZleV9tYXRfZGlmZiAlPiUgYXNfdGliYmxlKHJvd25hbWVzID0gInZhcmlhYmxlIikNCmNvcl9zX2RpZmYgPC0gc3VydmV5X3RpYl9kaWZmICU+JSBzZWxlY3QodmFyaWFibGUsZGlmZl9zYWYpICU+JSBmaWx0ZXIoZGlmZl9zYWY+MC4yNSB8IGRpZmZfc2FmIDwgLSAwLjI1KQ0KY29yX3NfZGlmZg0KYGBgDQogT25lIG5vdGljZWFibGUgdGhpbmcgaXMgdGhhdCB0aGVyZSBpcyBhIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gYmxhY2tfcGVyIGFuZCBkaWZmX3NhZi4gVGhpcyBtZWFucyB0aGF0IGJsYWNrIHBvcHVsYXRpb24gZmVlbHMgbGVzcyBzYWZlICBhbHNvIHRoZXJlJ3MgYSBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBzcGVkX3BlcmNlbnQgYW5kIGRpZmZfc2FmICB0aGUgc3R1ZGVudCBwYXJ0aWNpcGF0aW5nIGluIHNwZWNpYWwgZWR1Y2F0aW9uIGFsc28gZmVlbCBsZXNzIHNhZmUgLCBkdWUgdG8gc28gbWFueSByZWFzb25zDQoNCg==